//-----------------------------------------------------------------------
// <copyright file="IntegrateSourceDepot.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Simon Ransom</author>
// <email></email>
// <date>2004-03-23</date>
// <summary>Check that a particular product is installed, such as Microsoft Visual Studio .NET</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks
{
    using System;
    using System.Text;
    using System.Xml;
    using System.Globalization;
    using System.IO;
    using Microsoft.Build.Framework;
    using Microsoft.Sdc.Tasks.Configuration.InstalledProducts;

    /// <summary>
    /// Check that a particular product is installed, such as Microsoft Visual Studio .NET
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[
    /// <CheckProductInstalled Names="names" Versions="versions" NameComparisonOperators="nameComparisonOperators" 
    ///                         VersionComparisonOperators="versionComparisonOperators" UnaryOperators="unaryOperators" InstalledProductsXml="installedProductsXml">
    ///     <Output TaskParameter="Summary" ItemName="SummaryItem" />
    ///     <Output TaskParameter="Success" ItemName="SuccessItem" />
    /// </CheckProductInstalled>
    /// ]]></code>
    /// <para>where:</para>
    /// <para><i>names (Required)</i></para>
    /// <para>Names of the products to be checked for, for example, "Microsoft Visual Studio .NET"
    /// </para>
    /// <para><i>versions (Required)</i></para>
    /// <para>The versions of products to be checked for. Wildcard can be specified as an asterisk. Version must be numeric and separated by either "." or ","
    /// </para>
    /// <para><i>nameComparisonOperators (Required)</i></para>
    /// <para>Name comparison operators for each of the product names speciifed in <i>names</i>. Can be any of:
    ///         "Equals",
    ///         "Contains"
    ///         "LessThan"
    ///         "GreaterThan"
    ///         "LessThanOrEquals"
    ///         "GreaterThanOrEquals"
    /// </para>
    /// <para><i>versionComparisonOperators (Required)</i></para>
    /// <para>Name comparison operators for each of the product versions speciifed in <i>versions</i>. Can be any of:
    ///         "Equals",
    ///         "Contains"
    ///         "LessThan"
    ///         "GreaterThan"
    ///         "LessThanOrEquals"
    ///         "GreaterThanOrEquals"
    /// </para>
    /// <para><i>unaryOperators (Required)</i></para>
    /// <para>Unary operators for the respective <i>nameComparisonOperators</i>, allowing (for example) "Not Equals" to be created. Can be "None" or "Not".</para>
    /// <para><i>installedProductsXml (Required)</i></para>
    /// <para>A list of the products installed on the local machine. This will typically be generated by the <seealso cref="Microsoft.Sdc.Tasks.GetInstalledProducts"/> task</para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <CheckProductInstalled
    ///             Names="NDoc" Versions="1.2.0" NameComparisonOperators="Equals" VersionComparisonOperators="Equals" UnaryOperators="None" InstalledProductsXml="@(InstalledProductsXmlItem)">
    ///                     <Output TaskParameter="Summary" ItemName="SummaryItem" />
    ///                     <Output TaskParameter="Success" ItemName="SuccessItem" />
    ///         </CheckProductInstalled>
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class CheckProductInstalled : TaskBase
    {
        private string summary;
        private bool success;
        private string[] names;
        private string[] versions;
        private string[] nameComparisonOperators;
        private string[] versionComparisonOperators;
        private string[] unaryOperators;
        private string installedProductsXml;
        private bool suppressWarnings = false;

        /// <summary>
        /// Set to true in order to suppress warnings reported by this task 
        /// </summary>
        /// <value>true or false (defaults to false)</value>
        public bool SuppressWarnings
        {
            get
            {
                return this.suppressWarnings;
            }
            set
            {
                this.suppressWarnings = value;
            }
        }

        /// <summary>
        /// Textual summary of products found and products not found
        /// </summary>
        [Output]
        public string[] Summary
        {
            get
            {
                return new string[] { summary };
            }
        }

        /// <summary>
        /// Success of the checking after execution.
        /// </summary>
        [Output]
        public string[] Success
        {
            get
            {
                return new string[] { Convert.ToString(success) };
            }
        }

        /// <summary>
        /// Names of the products to be checked for.
        /// </summary>
        /// <example>Microsoft Visual Studio .NET</example>
        [Required]
        public string[] Names
        {
            get
            {
                return names;
            }
            set
            {
                this.names = value;
            }
        }

        /// <summary>
        /// Versions of products to be checked for
        /// </summary>
        /// <remarks>Wildcard can be specified as an asterisk. Version must be numeric and separated by either "." or ","</remarks>
        [Required]
        public string[] Versions
        {
            get
            {
                return versions;
            }
            set
            {
                this.versions = value;
            }
        }

        /// <summary>
        /// Name comparison operators taken from BinaryComparisonOperator enumeration.
        /// </summary>
        /// <seealso cref="Microsoft.Sdc.Tasks.Configuration.InstalledProducts.BinaryComparisonOperator"/>
        public string[] NameComparisonOperators
        {
            get
            {
                return nameComparisonOperators;
            }
            set
            {
                this.nameComparisonOperators = value;
            }
        }


        /// <summary>
        /// Version comparison operators taken from BinaryComparisonOperator enumeration.
        /// </summary>
        /// <seealso cref="Microsoft.Sdc.Tasks.Configuration.InstalledProducts.BinaryComparisonOperator"/>
        public string[] VersionComparisonOperators
        {
            get
            {
                return versionComparisonOperators;
            }
            set
            {
                this.versionComparisonOperators = value;
            }
        }

        /// <summary>
        /// Unary operators taken from UnaryLogicalOperator enumeration.
        /// </summary>
        /// <example>Not or None</example>
        /// <seealso cref="Microsoft.Sdc.Tasks.Configuration.InstalledProducts.UnaryLogicalOperator"/>
        public string[] UnaryOperators
        {
            get
            {
                return unaryOperators;
            }
            set
            {
                this.unaryOperators = value;
            }
        }

        /// <summary>
        /// Generated by GetInstalledProducts task
        /// </summary>
        [Required]
        public string InstalledProductsXml
        {
            get
            {
                return installedProductsXml;
            }
            set
            {
                this.installedProductsXml = value;
            }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            // Convert list of installed products to ProductList
            InstalledProductManager mgr = new InstalledProductManager();
            ProductList installedProducts = mgr.ConvertFromXml(installedProductsXml);
            bool isSuccessful = true;

            // TODO: Validate array lengths 
            if ((names.Length != NameComparisonOperators.Length) ||
                (nameComparisonOperators.Length != unaryOperators.Length) ||
                (unaryOperators.Length != versionComparisonOperators.Length))
            {
                throw new TaskException("InstalledProducts.PropertyMismatch");
            }


            StringBuilder summary = new StringBuilder();
            // Loop through each of the names of the required products testing against installed products
            for (int i = 0; i < names.Length; i++)
            {
                // Name Comparison
                BinaryComparisonOperator nameComparisonOperator =
                    ((nameComparisonOperators != null) && (nameComparisonOperators[i] != null) && (nameComparisonOperators[i].Length > 0)) ?
                        (BinaryComparisonOperator) Enum.Parse(typeof(BinaryComparisonOperator), nameComparisonOperators[i]) : BinaryComparisonOperator.Equals;

                // Version Comparison
                BinaryComparisonOperator versionComparisonOperator =
                    ((versionComparisonOperators != null) && (versionComparisonOperators[i] != null) && (versionComparisonOperators[i].Length > 0)) ?
                    (BinaryComparisonOperator) Enum.Parse(typeof(BinaryComparisonOperator), versionComparisonOperators[i]) : BinaryComparisonOperator.Equals;

                // Negate?
                UnaryLogicalOperator unaryOp =
                    ((unaryOperators != null) && (unaryOperators[i] != null) && (unaryOperators[i].Length > 0)) ?
                    (UnaryLogicalOperator) Enum.Parse(typeof(UnaryLogicalOperator), unaryOperators[i]) : UnaryLogicalOperator.None;

                Criteria criteria = new Criteria();
                mgr.AddForAnd(
                    criteria,
                    new Criterion(
                    typeof(Product).GetProperty("Name"),
                    new StringComparisonChecker(nameComparisonOperator),
                    names[i]
                    ));

                // If a version has been specified, always perform equals match (alhough wildcards are allowed)
                if (versions != null && versions[i] != null && (i < versions.Length) && versions[i].Length > 0)
                {
                    mgr.AddForAnd(
                        criteria,
                        new Criterion(
                        typeof(Product).GetProperty("Version"),
                        new VersionComparisonChecker(versionComparisonOperator),
                        versions[i]
                        ));
                }

                Product matchingProduct = mgr.GetMatchingInstalledProduct(criteria, installedProducts);
                if (matchingProduct != null)
                {
                    StringBuilder productSummary = new StringBuilder();
                    productSummary.Append("'");
                    productSummary.Append(matchingProduct.Name);
                    productSummary.Append("' ");
                    productSummary.Append(TaskResources.GetString("Version"));
                    productSummary.Append(" '");
                    productSummary.Append(matchingProduct.Version);
                    productSummary.Append("'");

                    if (unaryOp == UnaryLogicalOperator.Not)
                    {
                        isSuccessful = false;

                        summary.Append(String.Format(CultureInfo.InvariantCulture,TaskResources.GetString("InstalledProducts.BadProduct"), productSummary));
                        summary.Append(" ");
                        Log.LogError("InstalledProductsBadProduct", productSummary);
                    }
                    else
                    {
                        summary.Append(String.Format(CultureInfo.InvariantCulture,TaskResources.GetString("InstalledProducts.RequiredProduct"), productSummary));
                    }

                    summary.Append(Environment.NewLine);
                }
                else
                {
                    if (unaryOp == UnaryLogicalOperator.Not)
                    {
                        // Correctly did not match criteria
                        summary.Append(TaskResources.GetString("InstalledProducts.CorrectMatchFailed"));
                        summary.Append(" ");
                        summary.Append(criteria.ToString());
                    }
                    else
                    {
                        string errorMsg = String.Format(CultureInfo.InvariantCulture,TaskResources.GetString("InstalledProducts.NotFound"), criteria.ToString());
                        summary.Append(errorMsg);
                        if (suppressWarnings == false)
                        {
                            Log.LogError("InstalledProducts.NotFound", criteria.ToString());
                        }
                        isSuccessful = false;
                    }
                }
            }
            this.summary = summary.ToString();
            this.success = isSuccessful;
        }

        /// <summary>
        /// Initializes a new instance of the CheckProductInstalled class.
        /// </summary>
        public CheckProductInstalled()
        {
        }
    }
}